package com.springboot.springbootredis.distribute.key.impl;

import com.springboot.springbootredis.distribute.annotation.CacheLock;
import com.springboot.springbootredis.distribute.annotation.CacheParam;
import com.springboot.springbootredis.distribute.key.CacheKeyGenerator;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @Author: TongRui乀
 * @Date: 2019/1/25 16:38
 * @description： 自定义缓存key的生成实现
 */
@Component
public class CacheKeyGeneratorImpl implements CacheKeyGenerator {


    @Override
    public String getLockCacheKey(ProceedingJoinPoint pjp) {

        Signature signature = (MethodSignature)pjp.getSignature();

        Method method = ((MethodSignature) signature).getMethod();

        // CacheLock 注解
        CacheLock lockAnnotation = method.getAnnotation(CacheLock.class);

        Object[] args = pjp.getArgs();

        Parameter[] parameters = method.getParameters();

        StringBuilder builder = new StringBuilder();

        for (int i = 0; i < parameters.length; i++) {
            final CacheParam annotation = parameters[i].getAnnotation(CacheParam.class);
            if (annotation == null) {
                continue;
            }
            builder.append(lockAnnotation.delimiter()).append(args[i]);
        }
        if (StringUtils.isEmpty(builder.toString())) {
            final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            for (int i = 0; i < parameterAnnotations.length; i++) {
                final Object object = args[i];
                final Field[] fields = object.getClass().getDeclaredFields();
                for (Field field : fields) {
                    final CacheParam annotation = field.getAnnotation(CacheParam.class);
                    if (annotation == null) {
                        continue;
                    }
                    field.setAccessible(true);
                    builder.append(lockAnnotation.delimiter()).append(ReflectionUtils.getField(field, object));
                }
            }
        }
        return lockAnnotation.prefix() + builder.toString();
    }
}
